﻿using System;
using System.Collections;
using System.Reflection;

namespace ErrorDumper {
    class EnumerableHelper {
        public static bool Each(object enumerable, Action<object> action) {
            if (action == null)
                throw new ArgumentNullException("action");
            if (enumerable == null)
                return false;

            object enumerator = null;

            var typedEnumerable = enumerable as IEnumerable;
            if (typedEnumerable != null)
                try { enumerator = typedEnumerable.GetEnumerator(); }
                catch { enumerator = null; }

            if (enumerator == null)
                try { enumerator = enumerable.GetType().InvokeMember("GetEnumerator", BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null, enumerable, null); }
                catch { enumerator = null; }

            if (enumerator == null)
                return false;

            _Each(enumerator, action);
            return true;
        }

        static void _Each(object enumerator, Action<object> action) {
            var typedEnumerator = enumerator as IEnumerator;
            if (typedEnumerator != null) {
                for (; ; ) {
                    try {
                        if (!typedEnumerator.MoveNext())
                            break;
                    }
                    catch {
                        break;
                    }

                    try { action(typedEnumerator.Current); }
                    catch { }
                }
                return;
            }

            var enumeratorType = enumerator.GetType();
            for (; ; ) {
                try {
                    if (!(bool)enumeratorType.InvokeMember("MoveNext", BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null, enumerator, null))
                        break;
                }
                catch {
                    break;
                }

                try { action(enumeratorType.InvokeMember("Current", BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty, null, enumerator, null)); }
                catch { }
            }
        }
    }
}
